package com.zhiwei.codesecurity.service.taskAdd;

import com.zhiwei.codesecurity.common.base.ServiceResponse;
import com.zhiwei.codesecurity.common.constants.Constants;
import com.zhiwei.codesecurity.common.constants.ResourcesPropertiesConstants;
import com.zhiwei.codesecurity.common.enums.JobConfigType;
import com.zhiwei.codesecurity.common.enums.JobType;
import com.zhiwei.codesecurity.common.enums.RemoteType;
import com.zhiwei.codesecurity.common.enums.UploadType;
import com.zhiwei.codesecurity.common.utils.*;
import com.zhiwei.codesecurity.entity.Interfaces;
import com.zhiwei.codesecurity.entity.Projects;
import com.zhiwei.codesecurity.entity.ScheduleJob;
import com.zhiwei.codesecurity.entity.Teams;
import com.zhiwei.codesecurity.mapper.*;
import com.zhiwei.codesecurity.service.schedulejob.ScheduleJobService;
import com.zhiwei.codesecurity.service.taskadd.ITaskAddService;
import com.zhiwei.codesecurity.service.taskadd.request.TaskAddReq;
import com.zhiwei.codesecurity.service.taskadd.response.TaskAddRlt;
import com.zhiwei.codesecurity.service.taskadd.response.TeamDetail;
import com.zhiwei.codesecurity.service.taskadd.response.TeamDetailServRlt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;

@Service("taskAddService")
public class TaskAddServiceImpl implements ITaskAddService {
    private final static Logger logger = LoggerFactory.getLogger(TaskAddServiceImpl.class);

    @Autowired
    private ProjectsDao projectsDao;

    @Autowired
    private InterfacesDao interfacesDao;

    @Autowired
    private ScheduleJobDao scheduleJobDao;

    @Autowired
    private ScheduleJobService scheduleJobService;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Autowired
    private ProjectsMapper projectsMapper;

    @Autowired
    private TeamsMapper teamsMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public ServiceResponse<TaskAddRlt> taskAdd(final TaskAddReq request) {
        logger.info(">>>>>> taskAdd start ... ");
        // 请求参数验证
        if (null == request) {
            logger.error("=== 请求参数为空|request= {}", request);
            return ServiceResponseUtil.createServiceResponseForParamError("请求参数为空!");
        }

        // 将请求对象转换为数据库Model对象
        final Projects projects = new Projects();
        BeanUtil.copyPropertiesQuietly(request, projects);
        projects.setId(IdWorker.generate());
        projects.setFileName(null); // 将用户上传的文件名置为空，后面处理文件后再更新
        projects.setFileFilter(StringUtils.arr2string(request.getFileFilter(), ","));
        projects.setDirectoryFilter(StringUtils.arr2string(request.getDirectoryFilter(), ","));
        projects.setInterfaceList(StringUtils.arr2string(request.getInterfaceList(), ","));
        projects.setSubmitReceivers(StringUtils.arr2string(request.getSubmitReceivers(), ","));
        projects.setFailedReceivers(StringUtils.arr2string(request.getFailedReceivers(), ","));
        projects.setSuccessReceivers(StringUtils.arr2string(request.getSuccessReceivers(), ","));
        projects.setRepeatMonth(StringUtils.arr2string(request.getRepeatMonth(), ","));
        projects.setRepeatWeek(StringUtils.arr2string(request.getRepeatWeek(), ","));
        projects.setDataVersion(1);


        // 添加新项目
        final int projectsRlt = projectsDao.add(projects);
        logger.info("=====任务新建结果|projectsRlt = {}", projectsRlt);

        List<ScheduleJob> scheduleJobList = new ArrayList<>();
        ScheduleJob scheduleJob;
        for (int i = 0; i < request.getInterfaceList().size(); i++) {
            scheduleJob = new ScheduleJob();
            scheduleJob.setProjectId(projects.getId());
            scheduleJob.setInterfaceId(request.getInterfaceList().get(i));
            scheduleJob.setScheduleJobId(IdWorker.generate());
            scheduleJob.setStatus(Constants.SCHEDULE_JOB_STATE_RUN);
            scheduleJob.setIsSync(0);
            AddJobDetailByInterfaceId(scheduleJob);
            if (projects.getJobType() == JobType.IMMEDIATE_EXEC.getKey()) { // 立即执行
                logger.info("=====开始新建定时任务：立即执行===========");
                String cronExpression = ComputeCronExpression(projects, null);
                scheduleJob.setCronExpression(cronExpression);
                scheduleJobDao.add(scheduleJob);
                logger.info("=====结束新建定时任务：立即执行|scheduleJob = {}", scheduleJob);
            } else if (projects.getJobType() == JobType.PLAN_EXEC.getKey()) { // 计划执行
                if (projects.getJobConfigType() == JobConfigType.FIXED_EXEC.getKey()) { // 定时执行
                    logger.info("=====开始新建定时任务：计划执行|定时执行=================");
                    String cronExpression = ComputeCronExpression(projects, JobConfigType.FIXED_EXEC);
                    scheduleJob.setCronExpression(cronExpression);
                    scheduleJobDao.add(scheduleJob);
                    logger.info("=====结束新建定时任务：计划执行|定时执行|scheduleJob = {}", scheduleJob);
                } else if (projects.getJobConfigType() == JobConfigType.REPEAT_EXEC.getKey()) { // 重复执行
                    // 待实现
                    logger.info("=====开始新建定时任务：计划执行|重复执行=================");
                    String cronExpression = ComputeCronExpression(projects, JobConfigType.REPEAT_EXEC);
                    scheduleJob.setCronExpression(cronExpression);
                    scheduleJobDao.add(scheduleJob);
                    logger.info("=====结束新建定时任务：计划执行|重复执行|scheduleJob = {}", scheduleJob);
                }
            }
            scheduleJobList.add(scheduleJob);
        }

        if (scheduleJobList.size() > 0) {
            for (int i = 0; i < scheduleJobList.size(); i++) {
                ScheduleJob job = scheduleJobList.get(i);
                scheduleJobService.StartScheduleJob(job);
            }
        }

        TaskAddRlt taskAddRlt = new TaskAddRlt();
        taskAddRlt.setProjectId(String.valueOf(projects.getId()));
        ServiceResponse<TaskAddRlt> rlt = ServiceResponseUtil.createServiceResponse(taskAddRlt);
        logger.info(">>>>>> rlt = {}", rlt);

        if (projects.getUploadType().intValue() == UploadType.LOCAL_UPLOAD.getKey().intValue()) {
            taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    // 根据projects，将用户上传的zip文件解压缩后，进行处理，然后再压缩成zip包，并将zip文件名写入projects
                    String fileName = request.getFileName().replace(".zip", "");
                    String zipFileAddress = ResourcesPropertiesConstants.LOCAL_DOWNLOAD_DIR + request.getFileName();
                    FileUtils.ZipToFile2(ResourcesPropertiesConstants.TEMP_DIR + request.getFileName(),
                            ResourcesPropertiesConstants.TEMP_DIR);
                    // 对文件或目录进行过滤处理。
                    FileUtils.FileToZip2(ResourcesPropertiesConstants.TEMP_DIR + fileName, zipFileAddress);
                    projects.setFileName(zipFileAddress);
                    projects.setUpdateTime(new Date());
                    projects.setDataVersion(projects.getDataVersion() + 1);
                    projectsDao.update(projects);
                }
            });
        }
        logger.info(">>>>>> taskAdd end ... ");
        return rlt;
    }

    /**
     * 从GIT或SVN远程下载需要扫描的代码文件，处理后压缩成ZIP文件，将文件名写入Projects中
     */
    public void downSvnAndGitFileToZip() {
        logger.info(">>>>>> downSvnAndGitFileToZip start ... ");
        List<Projects> projectsList = projectsMapper.getUnDownLoadSvnAndGitFiles();
        if (null != projectsList && projectsList.size() > 0) {
            Projects projects;
            for (int i = 0; i < projectsList.size(); i++) {
                projects = projectsList.get(i);
                String fileName = UUIDUtil.getUUID();
                String srcDirectory = ResourcesPropertiesConstants.TEMP_DIR + fileName;
                String zipFileAddress = ResourcesPropertiesConstants.GIT_DOWNLOAD_DIR + fileName + ".zip";
                if (projects.getRemoteType().intValue() == RemoteType.SVN.getKey().intValue()) { // SVN
                    SVNUtils svnUtils = new SVNUtils(projects.getSvnGitUsername(), projects.getSvnGitPwd());
                    File workingCopy = new File(srcDirectory);
                    if (workingCopy.exists()) {
                        workingCopy.delete();
                    }
                    workingCopy.mkdirs();
                    svnUtils.checkout(projects.getSvnGitUrl(), workingCopy, true);
                    FileUtils.FileToZip2(srcDirectory, zipFileAddress);

                } else if (projects.getRemoteType().intValue() == RemoteType.GIT.getKey().intValue()) { // GIT
                    JGitUtils.cloneRepository(projects.getSvnGitUrl(), projects.getSvnGitUsername(),
                            projects.getSvnGitPwd(), projects.getGitBranchname(), srcDirectory);
                    FileUtils.FileToZip2(srcDirectory, zipFileAddress);
                }

                File zipFile = new File(zipFileAddress);
                if (!zipFile.exists()) { // 退出本次循环，处理下一条记录
                    continue;
                }
                projects.setFileName(zipFileAddress);
                projects.setUpdateTime(new Date());
                projects.setDataVersion(projects.getDataVersion() + 1);
                projectsDao.update(projects);
            }
        }
        logger.info(">>>>>> downSvnAndGitFileToZip end ... ");
    }

    public ServiceResponse<TeamDetailServRlt> getTeamSetting() {
        logger.info(">>>>>> getTeamSetting start ... ");
        List<Teams> teamsList = teamsMapper.getAllTeams();
        if (null == teamsList || teamsList.size() == 0) {
            logger.info(">>>>>>>>>团队没有为空，没有记录!");
            return ServiceResponseUtil.createServiceResponseForParamError("团队没有为空，没有记录!");
        }

        Hashtable<String, Teams> teamsHashtable = new Hashtable<>();
        for (int i = 0; i < teamsList.size(); i++) {
            Teams ts = teamsList.get(i);
            String teamId = String.valueOf(ts.getId());
            teamsHashtable.put(teamId, ts);
        }

        TeamDetailServRlt teamDetailServRlt = new TeamDetailServRlt();
        List<TeamDetail> teamDetailList = new ArrayList<>();
        teamDetailServRlt.setDatas(teamDetailList);
        TeamDetail teamDetail;
        Teams teams;
        for (int i = 0; i < teamsList.size(); i++) {
            teamDetail = new TeamDetail();
            teams = teamsList.get(i);
            teamDetail.setTeamId(String.valueOf(teams.getId()));
          /*  teamDetail.setTeamName(getSettingTeamName(teams, teamsHashtable));*/
            teamDetailServRlt.getDatas().add(teamDetail);
        }

        ServiceResponse<TeamDetailServRlt> rlt = ServiceResponseUtil.createServiceResponse(teamDetailServRlt);
        logger.info(">>>>>> rlt = {}", rlt);
        logger.info(">>>>>> getTeamSetting end ... ");
        return rlt;

    }

    /**
     * 获取指定Team的SettingTeamName
     * @param teams
     * @param allTeams
     * @return
     */
/*    private String getSettingTeamName(final Teams teams,  final Hashtable<String, Teams> allTeams) {
        String settingTeamName = teams.getTeamName();
        Teams tempTeams = teams;
        while (!tempTeams.getParentId().equals(0L)) {
            tempTeams = getParentTeam(tempTeams, allTeams);
            settingTeamName = tempTeams.getTeamName() + "/" + settingTeamName;
        }
        logger.info(">>>>>>>>>>>>settingTeamName:{}", settingTeamName);
        return settingTeamName;
    }*/

    /**
     * 获取指定Teams的父Teams
     * @param teams
     * @param allTeams
     * @return
     */
  /*  private Teams getParentTeam( final Teams teams,   final Hashtable<String, Teams> allTeams) {
        Teams parentTeam = null;
        Long teamId = teams.getParentId();
        parentTeam = allTeams.get(String.valueOf(teamId));
        return parentTeam;
    }
*/
    /**
     * 根据根据interfaceId获取:JOB_NAME, ALIAS_NAME, JOB_CLASS, JOB_GROUP, JOB_TRIGGER
     * @param scheduleJob
     */
    private void AddJobDetailByInterfaceId(ScheduleJob scheduleJob) {
        String interfaceId = scheduleJob.getInterfaceId();
        Interfaces interfaces = interfacesDao.getByPrimaryKey(interfaceId);
        if (null != interfaces) {
            String randomIdStr = IdMaker.generate();
            scheduleJob.setJobName(interfaces.getInterfaceName() + randomIdStr);
            scheduleJob.setAliasName(interfaces.getInterfaceName() + randomIdStr);
            scheduleJob.setJobClass(interfaces.getJobClass());
            scheduleJob.setJobGroup(interfaces.getJobGroup());
        }
    }

    /**
     * 计算Cron表达式
     * @param projects
     * @param jobConfigType
     * @return
     */
    private String ComputeCronExpression(Projects projects, JobConfigType jobConfigType) {
        String cronRlt = "";
        if (projects.getJobType() == JobType.IMMEDIATE_EXEC.getKey()) { // 立即执行
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.MINUTE, 1); // 1分钟之后
            String currentTime = DateUtils.format(calendar.getTime(), DateUtils.FORMAT_MM);
            String[] currentTimeSplit = currentTime.split("-| |:");
            String year = currentTimeSplit[0];
            String month = String.valueOf(Integer.parseInt(currentTimeSplit[1]));
            String day = String.valueOf(Integer.parseInt(currentTimeSplit[2]));
            String hour = String.valueOf(Integer.parseInt(currentTimeSplit[3]));
            String minute = String.valueOf(Integer.parseInt(currentTimeSplit[4]));
            cronRlt = "0 " + minute + " " + hour + " " + day + " " + month + " ? " + year;
        } else if (projects.getJobType() == JobType.PLAN_EXEC.getKey()) { // 计划执行
            if (projects.getJobConfigType() == JobConfigType.FIXED_EXEC.getKey()) { // 定时执行
                 String fixedTime = projects.getFixedTime();
                String[] fixedTimeSplit = fixedTime.split("-| |:");
                String year = fixedTimeSplit[0];
                String month = String.valueOf(Integer.parseInt(fixedTimeSplit[1]));
                String day = String.valueOf(Integer.parseInt(fixedTimeSplit[2]));
                String hour = String.valueOf(Integer.parseInt(fixedTimeSplit[3]));
                String minute = String.valueOf(Integer.parseInt(fixedTimeSplit[4]));
                cronRlt = "0 " + minute + " " + hour + " " + day + " " + month + " ? " + year;
            } else if (projects.getJobConfigType() == JobConfigType.REPEAT_EXEC.getKey()) { // 重复执行
                Set<String> minuteAl = new HashSet<>(); // 重复执行分钟
                Set<String> hourAl = new HashSet<>(); // 重复执行小时
                Set<String> weekAl = new HashSet<>(); // 重复执行星期
                Set<String> monthAl = new HashSet<>(); // 重复执行月

                // 处理分钟和小时
                String[] timeSplit = projects.getRepeatTime().split(":");
                String hour = String.valueOf(Integer.parseInt(timeSplit[0]));
                String minute = String.valueOf(Integer.parseInt(timeSplit[1]));
                hourAl.add(hour);
                minuteAl.add(minute);

                // 处理星期
                String[] weekSplit = projects.getRepeatWeek().split(",");
                for (int i = 0; i < weekSplit.length; i++) {
                    weekAl.add(weekSplit[i]);
                }

                // 处理月
                String[] monthSplit = projects.getRepeatMonth().split(",");
                for (int i = 0; i < monthSplit.length; i++) {
                    monthAl.add(monthSplit[i]);
                }

                String cronSecond = "0";    // 秒（Seconds）; 0~59的整数; [, - * /]四个字符
                String cronMinute = "*";    // 分（Minutes）; 0~59的整数; [, - * /]四个字符
                String cronHour = "*";      // 小时（Hours）; 0~23的整数; [, - * /]四个字符
                String cronDay = "?";       // 日期（DayofMonth）;  	1~31的整数（但是你需要考虑你月的天数）;
                                            // [,- * ? / L W C]八个字符
                String cronMonth = "*";     // 月份（Month）; 1~12的整数或者 JAN-DEC; [, - * /]四个字符
                String cronWeek = "*";      // 星期（DayofWeek）; 	1~7的整数或者 SUN-SAT （1=SUN）;
                                            // [, - * ? / L C #]八个字符
                String cronYear = "*";      // 年(可选，留空)（Year）; 1970~2099;[, - * /]四个字符

                cronMinute = StringUtils.arr2string(minuteAl, ",");
                cronHour = StringUtils.arr2string(hourAl, ",");
                cronMonth = StringUtils.arr2string(monthAl, ",");

                cronWeek = "";
                for (String weekItem : weekAl) {
                    cronWeek = cronWeek + weekItem + ",";
                }
                cronWeek = cronWeek.substring(0, cronWeek.length() - 1);

                cronRlt = cronSecond + " " + cronMinute + " " + cronHour + " " + cronDay + " " + cronMonth + " "
                        + cronWeek + " " + cronYear;
            }
        }

        return cronRlt;
    }
}


